package org.mclll.xwangplugin.enchantment.listener;

import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.enchantments.EnchantmentOffer;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockDispenseArmorEvent;
import org.bukkit.event.enchantment.EnchantItemEvent;
import org.bukkit.event.enchantment.PrepareItemEnchantEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.entity.VillagerAcquireTradeEvent;
import org.bukkit.event.entity.VillagerReplenishTradeEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.*;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.mclll.xwangplugin.MclllCustom;
import org.mclll.xwangplugin.enchantment.config.EnchantmentLimitConfig;
import org.mclll.xwangplugin.enchantment.item.EnchantmentItem;
import org.mclll.xwangplugin.enchantment.player.PlayerLimit;
import org.mclll.xwangplugin.log.GlobalLog;
import org.mclll.xwangplugin.log.LogUtil;
import org.mclll.xwangplugin.log.LoggerFactory;

import java.util.*;

/**
 * @author 洛佑希
 */
public class EnchantmentListener implements Listener {
    private final MclllCustom plugin;
    LogUtil log = LoggerFactory.get(GlobalLog.class);
    // Map<玩家ID, Map<物品类型, Map<附魔花费, Map<附魔类型, 附魔等级>>>>
    public static Map<UUID, Map<Material, Map<Integer, Map<Enchantment, Integer>>>> playerEcmInfo;

    public EnchantmentListener(MclllCustom plugin) {
        this.plugin = plugin;
        playerEcmInfo = new HashMap<>();
    }

    // 附魔台相关
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onInsertEcmTable(PrepareItemEnchantEvent event) {
        // 获取附魔台提供的附魔
        EnchantmentOffer[] nowOffers = event.getOffers();
        // 获取附魔者
        Player enchanter = event.getEnchanter();
        UUID enchanterId = enchanter.getUniqueId();
        // 获取将要附魔的物品
        ItemStack item = event.getItem();
        Material material = item.getType();
        // 查找附魔者是否存在已有附魔表
        if (playerEcmInfo.containsKey(enchanterId)) {
            // 查找附魔者的附魔表中是否存在当前物品的附魔表
            boolean haveItem = playerEcmInfo.get(enchanterId).containsKey(material);
            if (haveItem) {
                // 获取附魔者的附魔表中当前物品的附魔表
                Map<Integer, Map<Enchantment, Integer>> itemOldOffers = playerEcmInfo.get(enchanterId).get(material);
                // 遍历当前offer 查找附魔表中是否存在与当前offer的选项cost相同的选项
                for (EnchantmentOffer offer : nowOffers) {
                    if (offer == null) {
                        continue;
                    }
                    if (itemOldOffers.containsKey(offer.getCost())) {
                        // 获取附魔表中对应cost的附魔 选取第一项附魔作为offer
                        replaceEcm(offer, itemOldOffers.get(offer.getCost()));
                    } else {
                        // 新生成一个对应cost的附魔 存入玩家附魔表中
                        Map<Enchantment, Integer> newEcmOffer = getNewEcmForItem(item, offer.getCost());
                        itemOldOffers.put(offer.getCost(), newEcmOffer);
                        // 选取第一项附魔作为offer
                        replaceEcm(offer, newEcmOffer);
                    }
                }
            } else {
                Map<Integer, Map<Enchantment, Integer>> itemNewOffers = new HashMap<>();
                for (EnchantmentOffer offer : nowOffers) {
                    if (offer == null) {
                        continue;
                    }
                    // 新生成一个对应cost的附魔 存入玩家附魔表中
                    Map<Enchantment, Integer> newOffer = getNewEcmForItem(item, offer.getCost());
                    itemNewOffers.put(offer.getCost(), newOffer);
                    // 选取第一项附魔作为offer
                    replaceEcm(offer, newOffer);
                }
                playerEcmInfo.get(enchanterId).put(material, itemNewOffers);
            }
        } else {
            // 未查到附魔者存在附魔表 生成新的附魔表
            Map<Material, Map<Integer, Map<Enchantment, Integer>>> newItemEcms = new HashMap<>();
            Map<Integer, Map<Enchantment, Integer>> newEcms = new HashMap<>();
            for (EnchantmentOffer offer : nowOffers) {
                if (offer == null) {
                    continue;
                }
                Map<Enchantment, Integer> newOffer = getNewEcmForItem(item, offer.getCost());
                newEcms.put(offer.getCost(), newOffer);
                replaceEcm(offer, newOffer);
            }
            newItemEcms.put(material, newEcms);
            playerEcmInfo.put(enchanterId, newItemEcms);
        }
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onClickEcmOption(EnchantItemEvent event) {
        // 获取附魔信息
        UUID enchanterId = event.getEnchanter().getUniqueId();
        Map<Enchantment, Integer> defaultEcm = event.getEnchantsToAdd();
        int enchantmentCost = event.getExpLevelCost();
        Material material = event.getItem().getType();
        // 清除原有附魔 使用附魔者对应附魔表进行覆写
        defaultEcm.clear();
        defaultEcm.putAll(playerEcmInfo.get(enchanterId).get(material).get(enchantmentCost));
        playerEcmInfo.remove(enchanterId);
    }

    private Map<Enchantment, Integer> getNewEcmForItem(ItemStack item, int enchantmentCost) {
        Map<Enchantment, Integer> newEcms = new HashMap<>();
        // 创建一个虚拟item并附魔
        ItemFactory ify = Bukkit.getItemFactory();
        ItemStack virtualItem = ify.enchantWithLevels(item, enchantmentCost, false, new Random());
        Map<Enchantment, Integer> virtualItemEcm = new HashMap<>();
        // 附魔物品为书需要使用其他方法获取附魔信息
        if (virtualItem.getType() == Material.ENCHANTED_BOOK) {
            EnchantmentStorageMeta newMeta = (EnchantmentStorageMeta) virtualItem.getItemMeta();
            for (Enchantment bookEnchantment : newMeta.getStoredEnchants().keySet()) {
                int level = newMeta.getStoredEnchantLevel(bookEnchantment);
                virtualItemEcm.put(bookEnchantment, level);
            }
        } else {
            // 获取虚拟item的附魔属性
            virtualItemEcm = new HashMap<>(virtualItem.getEnchantments());
        }
        // 检查虚拟item附魔属性
        Iterator<Map.Entry<Enchantment, Integer>> entries = virtualItemEcm.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<Enchantment, Integer> entry = entries.next();
            Enchantment enchantment = entry.getKey();
            int enchantmentLevel = entry.getValue();
            // 检查虚拟item附魔表中是否有被限制附魔
            if (EnchantmentLimitConfig.limitEnchantments.containsKey(enchantment)) {
                int limitLevel = EnchantmentLimitConfig.limitEnchantments.get(enchantment);
                if (limitLevel > 0) {
                    // 存在被限制附魔 取限制等级与当前等级的最小值加入新附魔表
                    newEcms.put(enchantment, Math.min(limitLevel, enchantmentLevel));
                } else {
                    if (newEcms.isEmpty() && !entries.hasNext()) {
                        // 虚拟item附魔表中无下一项附魔 且新附魔表为空 则重新生成虚拟item附魔表
                        virtualItem = ify.enchantWithLevels(item, enchantmentCost, false, new Random());
                        virtualItemEcm.clear();
                        if (virtualItem.getType() == Material.ENCHANTED_BOOK) {
                            EnchantmentStorageMeta newMeta = (EnchantmentStorageMeta) virtualItem.getItemMeta();
                            for (Enchantment bookEnchantment : newMeta.getStoredEnchants().keySet()) {
                                int level = newMeta.getStoredEnchantLevel(bookEnchantment);
                                virtualItemEcm.put(bookEnchantment, level);
                            }
                        } else {
                            virtualItemEcm.putAll(virtualItem.getEnchantments());
                        }
                        entries = virtualItemEcm.entrySet().iterator();
                    }
                }
            } else {
                // 不存在被限制附魔 直接将当前附魔加入新附魔表
                newEcms.put(enchantment, enchantmentLevel);
            }
        }
        return newEcms;
    }

    // 改变可视附魔
    public void replaceEcm(EnchantmentOffer offer, Map<Enchantment, Integer> newEcms) {
        Iterator<Map.Entry<Enchantment, Integer>> iterator = newEcms.entrySet().iterator();
        Map.Entry<Enchantment, Integer> entry = iterator.next();
        offer.setEnchantment(entry.getKey());
        offer.setEnchantmentLevel(entry.getValue());
    }

    // 铁砧相关
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onInsertAnvil(PrepareAnvilEvent event) {
        // 获取插入铁砧中的物品信息
        AnvilInventory inventory = event.getInventory();
        ItemStack oldResultItem = inventory.getResult();
        // 当铁砧中出现修改后的物品时
        if (oldResultItem != null) {
            // 获取物品的附魔信息
            Map<Enchantment, Integer> oldResultEcm = new HashMap<>();
            // 附魔书需要从Meta获取附魔信息
            if (oldResultItem.getType() == Material.ENCHANTED_BOOK) {
                EnchantmentStorageMeta newMeta = (EnchantmentStorageMeta) oldResultItem.getItemMeta();
                for (Enchantment bookEnchantment : newMeta.getStoredEnchants().keySet()) {
                    int level = newMeta.getStoredEnchantLevel(bookEnchantment);
                    oldResultEcm.put(bookEnchantment, level);
                }
            } else {
                oldResultEcm.putAll(oldResultItem.getEnchantments());
            }
            // 遍历物品的旧附魔信息
            for (Map.Entry<Enchantment, Integer> entry : oldResultEcm.entrySet()) {
                Enchantment enchantment = entry.getKey();
                // 查找该条附魔是否存在限制
                if (EnchantmentLimitConfig.limitEnchantments.containsKey(enchantment)) {
                    // 获取限制等级
                    int limitLevel = EnchantmentLimitConfig.limitEnchantments.get(enchantment);
                    if (limitLevel == 0) {
                        // 当限制等级为0时表示禁用附魔 直接修改附魔花费超过原版上限 使铁砧无法修改
                        // 创造模式下会无视本条规则
                        boolean haveOp = false;
                        List<HumanEntity> viewers = event.getViewers();
                        for (HumanEntity viewer : viewers) {
                            if (viewer.getGameMode() == GameMode.CREATIVE) {
                                haveOp = true;
                                break;
                            }
                        }
                        if (haveOp) {
                            break;
                        } else {
                            inventory.setRepairCost(40);
                            return;
                        }
                    }
                }
            }
            // 创建一份当前结果物品的副本作为新结果物品
            ItemStack newResultItem = EnchantmentItem.respawnNewItem(oldResultItem);
            event.setResult(newResultItem);
        }
    }

    // 打开容器相关
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onOpenInventory(InventoryOpenEvent event) {
        // log.info("inventory event trigger");
        Inventory inventory = event.getInventory();
        ItemStack[] itemStacks = inventory.getStorageContents();
        // log.info("max size=" + inventory.getSize());
        ItemStack[] newItemStacks = new ItemStack[inventory.getSize()];
        for (int i = 0; i < itemStacks.length; i++) {
            ItemStack item = itemStacks[i];
            if (item == null) {
                continue;
            }
            // log.info(item.toString());
            if (item.getType() == Material.ENCHANTED_BOOK) {
                newItemStacks[i] = EnchantmentItem.respawnNewItem(item);
//                EnchantmentStorageMeta meta = (EnchantmentStorageMeta) newItemStacks[i].getItemMeta();
//                if (meta.getStoredEnchants().isEmpty()) {
//                    newItemStacks[i] = new ItemStack(Material.BOOK);
//                }
            } else if (!item.getEnchantments().isEmpty()) {
                newItemStacks[i] = EnchantmentItem.respawnNewItem(item);
            } else {
                newItemStacks[i] = item;
            }
        }
        inventory.setContents(newItemStacks);
        PlayerLimit.clearPlayerEcm(event.getPlayer());
    }

    // 玩家拾取相关
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onPlayerPickup(EntityPickupItemEvent event) {
        // 获取拾取物品的实体
        LivingEntity entity = event.getEntity();
        // 判断拾取实体是否为Player
        if (entity.getType() == EntityType.PLAYER) {
            // 获取拾取的物品
            Item pickupItem = event.getItem();
            ItemStack pickupItemStack = pickupItem.getItemStack();
            // 判断拾取的物品是否为附魔书 是否有附魔
            if (!(pickupItemStack.getType() == Material.ENCHANTED_BOOK) && pickupItemStack.getEnchantments().isEmpty()) {
                return;
            }
            // 创建一份拾取物品的副本作为新拾取物品
            ItemStack newPickupItem = EnchantmentItem.respawnNewItem(pickupItemStack);
//            if (newPickupItem.getType() == Material.ENCHANTED_BOOK) {
//                EnchantmentStorageMeta newMeta = (EnchantmentStorageMeta) newPickupItem.getItemMeta();
//                if (newMeta.getStoredEnchants().isEmpty()) {
//                    newPickupItem = new ItemStack(Material.BOOK);
//                } else {
//                    newPickupItem.setItemMeta(newMeta);
//                }
//            }
            // 将拾取的物品改为修改后的新物品
            pickupItem.setItemStack(newPickupItem);
            PlayerLimit.clearPlayerEcm((HumanEntity) entity);
        }
    }

    // 盔甲架相关
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onPutOnArmour(BlockDispenseArmorEvent event) {
        ItemStack oldItem = event.getItem();
        ItemStack newItem = EnchantmentItem.respawnNewItem(oldItem);
        event.setItem(newItem);
    }

    // 村民交易相关
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onNewTrade(VillagerAcquireTradeEvent event) {
        MerchantRecipe recipe = checkTradeResult(event.getRecipe());
//        log.info(recipe.toString());
        event.setRecipe(recipe);
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onReplenishTrade(VillagerReplenishTradeEvent event) {
        MerchantRecipe recipe = checkTradeResult(event.getRecipe());
//        log.info(recipe.toString());
        event.setRecipe(recipe);
    }

    private MerchantRecipe checkTradeResult(MerchantRecipe recipe) {
        ItemStack resultItem = recipe.getResult();
        // 判断拾取的物品是否为附魔书 是否有附魔
        if ((resultItem.getType() == Material.ENCHANTED_BOOK) || !resultItem.getEnchantments().isEmpty()) {
            if (EnchantmentItem.haveLimitEnchant(resultItem)) {
                MerchantRecipe newRecipe = new MerchantRecipe(EnchantmentItem.respawnNewItem(resultItem), recipe.getUses(), recipe.getMaxUses(),
                        true, recipe.getVillagerExperience(), recipe.getPriceMultiplier(), recipe.getDemand(),
                        recipe.getSpecialPrice());
                newRecipe.setIngredients(recipe.getIngredients());
                newRecipe.setDemand(recipe.getDemand());
                return newRecipe;
            }
        }
        return recipe;
    }
}
